//
//  XLNetworking.m
//  JFCloundChat
//
//  Created by HuanGe on 2021/11/1.
//

#import "XLNetworking.h"
#import "AFNetworking.h"

@interface XLNetworking ()
@property (nonatomic, strong) AFURLSessionManager  * urlSessionManager;
@property (nonatomic, strong) NSMutableArray *managerArray;
@end


@implementation XLNetworking

static XLNetworking *_manager = nil;

#pragma mark ---------------------------------- 初始化 类
+ (instancetype)shareManager
{
    if (_manager == nil) {
        _manager = [[super alloc] init];
        _manager.timeOutSecond = 30;
        _manager.managerArray = [NSMutableArray array];
    }
    return _manager;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (_manager == nil) {
            _manager = [super allocWithZone:zone];
        }
    });
    return _manager;
}

- (id)copyWithZone:(nullable NSZone *)zone {
    return _manager;
}

- (id)mutableCopyWithZone:(nullable NSZone *)zone {
    return _manager;
}

#pragma mark ---------------------------------- 初始化 请求类
- (AFHTTPSessionManager *)requestManager:(XLRequestSerializerType)requestType responseType:(XLResponseSerializerType)responseType
{
    AFHTTPSessionManager *httpRequestManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:self.baseUrl]];
    if (requestType == XLRequestSerializerTypeHttp) {
        httpRequestManager.requestSerializer = [AFHTTPRequestSerializer serializer];
    }
    else if (requestType == XLRequestSerializerTypeJson) {
        httpRequestManager.requestSerializer = [AFJSONRequestSerializer serializer];
    }
    
    if (responseType == XLResponseSerializerTypeHttp) {
        httpRequestManager.responseSerializer = [AFHTTPResponseSerializer serializer];
    }
    else if (responseType == XLResponseSerializerTypeJson) {
        httpRequestManager.responseSerializer = [AFJSONResponseSerializer serializer];
    } 
    httpRequestManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",
                                                                    @"text/json",
                                                                    @"text/javascript",
                                                                    @"text/html",
                                                                    @"text/plain" ,nil];
    httpRequestManager.requestSerializer.timeoutInterval = self.timeOutSecond;
    
    [self.managerArray addObject:httpRequestManager];
    
    return httpRequestManager;
}
- (AFURLSessionManager *)urlSessionManager{
    if (_urlSessionManager == nil) {
        _urlSessionManager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
        
        [self.managerArray addObject:_urlSessionManager];
    }
    return _urlSessionManager;
}

#pragma mark ---------------------------------- 请求体基础参数

/// 常用基础参数

+ (NSMutableDictionary *)updateParmaWithBaseInfo:(NSDictionary *)dict
{
    if (dict == nil) {
        dict = [NSDictionary dictionary];
    }
    
    NSMutableDictionary *paramters = [NSMutableDictionary dictionaryWithDictionary:dict];
    return paramters;
}


+ (void)netWorkRequestResult:(NSString *)urlString
                andParamters:(NSDictionary *)paramtersDict
                     andTask:(NSURLSessionDataTask *)task
           andResponseObject:(id)responseObject
                    andError:(NSError *)error
                      andLog:(BOOL)log
          andResponseHandler:(ResponseBlock)responseHandler
{ 
    NSDictionary *responsedict = [NSDictionary dictionary];
    if (error) {
        NSLog(@"\nrequestUrl:%@\nresponseEr:\n%@", urlString, error.localizedDescription);
    }
    else{
        if ([responseObject isKindOfClass:[NSData class]]) {
            NSDictionary *responseObjectDict = [NSJSONSerialization JSONObjectWithData:responseObject
                                                                               options:NSJSONReadingMutableContainers
                                                                                 error:nil];
            responsedict = responseObjectDict;
        }
        else if ([responseObject isKindOfClass:[NSDictionary class]]) {
            responsedict = responseObject;
        } 
    }
    
    id data = nil;
    BOOL isSuccess = NO;
    NSString *message = error.localizedDescription;
    
    if (responsedict || responsedict.count == 0) {
        isSuccess = YES;
        data = responsedict;
    }
    else {
        message = @"ERROR";
    }
    if (responseHandler) {
        responseHandler(data, isSuccess, message);
    }
}

- (void)netWorkRequestWithMethod:(XLRequestMethod)method
        andRequestSerializerType:(XLRequestSerializerType)requestType
       andResponseSerializerType:(XLResponseSerializerType)responseType
                          andUrl:(NSString *)urlString
                    andParamters:(NSDictionary *)paramters
                andResponseBlock:(ResponseBlock)responseBlock
{
    NSAssert(self.baseUrl.length, @"please set baseUrl");
    
    AFHTTPSessionManager *sessionManager = [self requestManager:requestType responseType:responseType];
    if (paramters == nil ) {
        paramters = [NSDictionary dictionary];
    }
    NSMutableDictionary *paramtersDict = [NSMutableDictionary dictionaryWithDictionary:paramters];
    __weak __typeof(&*self) weakSelf = self;
    switch (method) {
        case XLRequestMethodGet:
        {
            paramtersDict = [XLNetworking updateParmaWithBaseInfo:paramtersDict];
            [sessionManager GET:urlString
                     parameters:paramtersDict
                        headers:nil
                       progress:nil
                        success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                [XLNetworking netWorkRequestResult:urlString
                                          andParamters:paramtersDict
                                               andTask:task
                                     andResponseObject:responseObject
                                              andError:nil
                                                andLog:YES
                                    andResponseHandler:responseBlock];
                __strong __typeof(&*self) strongSelf = weakSelf;
                [strongSelf.managerArray removeObject:sessionManager];
            }
                        failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                [XLNetworking netWorkRequestResult:urlString
                                          andParamters:paramtersDict
                                               andTask:task
                                     andResponseObject:nil
                                              andError:error
                                                andLog:YES
                                    andResponseHandler:responseBlock];
                __strong __typeof(&*self) strongSelf = weakSelf;
                [strongSelf.managerArray removeObject:sessionManager];
            }];
        }
            break;
        case XLRequestMethodPost:
        {
            paramtersDict = [XLNetworking updateParmaWithBaseInfo:paramtersDict];
            [sessionManager POST:urlString
                      parameters:paramtersDict
                         headers:nil
                        progress:nil
                         success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                [XLNetworking netWorkRequestResult:urlString
                                          andParamters:paramtersDict
                                               andTask:task
                                     andResponseObject:responseObject
                                              andError:nil
                                                andLog:YES
                                    andResponseHandler:responseBlock];
                __strong __typeof(&*self) strongSelf = weakSelf;
                [strongSelf.managerArray removeObject:sessionManager];
            }
                         failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                [XLNetworking netWorkRequestResult:urlString
                                          andParamters:paramtersDict
                                               andTask:task
                                     andResponseObject:nil
                                              andError:error
                                                andLog:YES
                                    andResponseHandler:responseBlock];
                __strong __typeof(&*self) strongSelf = weakSelf;
                [strongSelf.managerArray removeObject:sessionManager];
            }];
        }
            break;
        default:
            break;
    }
}
- (void)netWorkRequestUploadFileWithResponseSerializerType:(XLResponseSerializerType)responseType andUrl:(NSString *)urlString andParamters:(NSDictionary *)paramters andResponseBlock:(ResponseBlock)responseBlock
{}

- (void)netWorkRequestUploadFiles:(NSURL*)fileURL
        andResponseSerializerType:(XLResponseSerializerType)responseType
                           andUrl:(NSString *)urlString
                     andParamters:(NSDictionary *)paramters
                 andResponseBlock:(ResponseBlock)responseBlock
{
    NSAssert(self.baseUrl.length, @"please set baseUrl");
    
    AFHTTPSessionManager *sessionManager = [self requestManager:XLRequestSerializerTypeHttp responseType:responseType];
    
    if (paramters == nil ) {
        paramters = [NSDictionary dictionary];
    }
    
    NSMutableDictionary *paramtersDict = [NSMutableDictionary dictionaryWithDictionary:paramters];
    
    {
        paramtersDict = [XLNetworking updateParmaWithBaseInfo:paramtersDict];
        __weak __typeof(&*self) weakSelf = self;
        [sessionManager POST:urlString
                  parameters:paramtersDict
                     headers:nil
   constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
            if (fileURL.path.length) {
                NSString *mimeType = [XLNetworking mimeTypeForFileAtPath:fileURL.path];
                NSString *fileName = [fileURL.path componentsSeparatedByString:@"/"].lastObject;
                [formData appendPartWithFileURL:fileURL
                                           name:@"file"
                                       fileName:fileName
                                       mimeType:mimeType
                                          error:nil];
            }
        } progress:^(NSProgress * _Nonnull uploadProgress) {
            
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            [XLNetworking netWorkRequestResult:urlString
                                      andParamters:paramtersDict
                                           andTask:task
                                 andResponseObject:responseObject
                                          andError:nil
                                            andLog:YES
                                andResponseHandler:responseBlock];
            __strong __typeof(&*self) strongSelf = weakSelf;
            [strongSelf.managerArray removeObject:sessionManager];
        }
                     failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            [XLNetworking netWorkRequestResult:urlString
                                      andParamters:paramtersDict
                                           andTask:task
                                 andResponseObject:nil
                                          andError:error
                                            andLog:YES
                                andResponseHandler:responseBlock];
            __strong __typeof(&*self) strongSelf = weakSelf;
            [strongSelf.managerArray removeObject:sessionManager];
            
        }];
    }
}

- (void)downloadSourceWithUrl:(NSString *)urlString
                  andFilePath:(NSString *)filePath
                     progress:(void (^)(NSProgress *))downloadProgressBlock
            completionHandler:(void (^)(NSString * filePath, NSError *))completionHandler
{
    NSURL *url = [NSURL URLWithString:urlString];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    AFURLSessionManager *urlSessionManager = [[XLNetworking shareManager] urlSessionManager];
    __weak __typeof(&*self) weakSelf = self;
    NSURLSessionDownloadTask *downloadTask = [urlSessionManager downloadTaskWithRequest:request
                                                                               progress:^(NSProgress * _Nonnull downloadProgress) {
        if (downloadProgressBlock) {
            downloadProgressBlock(downloadProgress);
        }
    }
                                                                            destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        return [NSURL fileURLWithPath:filePath];
    }
                                                                      completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        if (completionHandler) {
            completionHandler(filePath.description, error);
        }
        __strong __typeof(&*self) strongSelf = weakSelf;
        [strongSelf.managerArray removeObject:urlSessionManager];
    }];
    [downloadTask resume];
}

- (void)cancelAllNetwork
{
    for (id item in self.managerArray) {
        if ([item isKindOfClass:[AFHTTPSessionManager class]]){
            AFHTTPSessionManager *requestManager = item;
            if (requestManager.tasks.count) {
                [requestManager.operationQueue cancelAllOperations];
            }
            if (requestManager.tasks.count) {
                [requestManager.operationQueue cancelAllOperations];
            }
        }
        else if ([item isKindOfClass:[AFURLSessionManager class]]){
            AFURLSessionManager *requestManager = item;
            if (requestManager.tasks.count) {
                [requestManager.operationQueue cancelAllOperations];
            }
        }
    }
}
/**
 获取文件的MIMEType
 超文本标记语言文本 .html,.html text/html
 　　普通文本 .txt text/plain
 　　RTF文本 .rtf application/rtf
 　　GIF图形 .gif image/gif
 　　JPEG图形 .jpeg,.jpg image/jpeg
 　　au声音文件 .au audio/basic
 　　MIDI音乐文件 mid,.midi audio/midi,audio/x-midi
 　　RealAudio音乐文件 .ra, .ram audio/x-pn-realaudio
 　　MPEG文件 .mpg,.mpeg video/mpeg
 　　AVI文件 .avi video/x-msvideo
 　　GZIP文件 .gz application/x-gzip
 　　TAR文件 .tar application/x-tar
 @param path 文件路径
 @return 文件MIMEType
 */

+ (NSString *)mimeTypeForFileAtPath:(NSString *)path
{
    NSURL *url = [NSURL fileURLWithPath:path];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    // 信号量
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    __block NSString *mimeType = nil;
    NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request
                                                             completionHandler:^(NSData * _Nullable data,
                                                                                 NSURLResponse * _Nullable response,
                                                                                 NSError * _Nullable error) {
        mimeType = response.MIMEType;
        dispatch_semaphore_signal(semaphore);
    }];
    [task resume];
    // 等待信号量
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    return mimeType;
}
@end
